﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SimpleData.ObjectModel;
using Autofac;
using System.Diagnostics.Contracts;

namespace SimpleData.Infrastructure.Plugins
{
	/// <summary>
	/// Porta de entrada para as evoluções na plataforma
	/// </summary>
	public sealed class Plug : IPlug
	{
		private IContainer container = null;
		private ContainerBuilder iocBuilder = null;

		/// <summary>
		/// Inicializa um novo container
		/// </summary>
		public Plug()
		{
			this.iocBuilder = new ContainerBuilder();
		}

		/// <summary>
		/// Realiza a conexão entre um provider que pode ser plugado
		/// </summary>
		/// <typeparam name="TPluggable"></typeparam>
		/// <returns></returns>
		public PlugConnectorBuilder<TPluggable> Connect<TPluggable>()
			where TPluggable : IPluggable
		{
			if ( this.iocBuilder == null )
				throw new InvalidOperationException( "O container IoC já foi construído." );

			return new PlugConnectorBuilder<TPluggable>( this.iocBuilder );
		}

		/// <summary>
		/// Constroi o container
		/// </summary>
		public void BuildContainer()
		{
			if ( this.iocBuilder != null )
			{
				if ( this.container != null )
					this.container.Dispose();

				this.iocBuilder.RegisterInstance<IPlug>( this );
				this.container = this.iocBuilder.Build();
				this.iocBuilder = null;
			}
		}

		/// <summary>
		/// Realiza a criação do plugin <paramref name="TPluggable"/>.
		/// </summary>
		/// <typeparam name="TPluggable"></typeparam>
		/// <returns></returns>
		public TPluggable Create<TPluggable>()
			where TPluggable : IPluggable
		{
			return this.Create<TPluggable>( ( string )null );
		}

		/// <summary>
		/// Realiza a criação do plugin <paramref name="TPluggable"/>
		/// </summary>
		/// <typeparam name="TPluggable"></typeparam>
		/// <param name="name"></param>
		/// <returns></returns>
		public TPluggable Create<TPluggable>( IDataObjectName name )
			where TPluggable : IPluggable
		{
			return this.Create<TPluggable>( name == null ? ( string )null : name.FullName );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="name"></param>
		/// <param name="type"></param>
		/// <returns></returns>
		public object Create( IDataObjectName name, Type type )
		{
			Contract.Requires<ArgumentNullException>( name != null, "name" );
			Contract.Requires<ArgumentNullException>( type != null, "type" );

			return this.container.ResolveNamed( name.FullName, type );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="TPluggable"></typeparam>
		/// <param name="name"></param>
		/// <returns></returns>
		internal TPluggable Create<TPluggable>( string name )
			where TPluggable : IPluggable
		{
			if ( String.IsNullOrEmpty( name ) )
				return this.container.Resolve<TPluggable>();
			else
				return this.container.ResolveNamed<TPluggable>( name );
		}
	}

	
}
